Conversation
v0.15.0のPR#14マージ以降の全変更をfeature/v0.15.1に移行:
- SVバックエンド品質改善: 定数ビット幅推論・else if正規化・冗長除去
- always_ff/always_comb/always_latch キーワード直接サポートと自動判別
- SV構文拡張Phase1: bit[N]型・assign文・inoutサポート
- SV構文拡張Phase2: enum→typedef enum・struct→struct packed・function→function automatic
- SV連接({a,b})・複製({N{expr}})構文のフルパイプライン実装
- 全60テストPASS
There was a problem hiding this comment.
Pull request overview
Cm の SystemVerilog バックエンド v0.15.1 として、SV 向けの構文・型・コード生成を拡張し、周辺ドキュメント/テスト/バージョン表記を更新する PR です。
Changes:
- SV 向けに
always(_ff/_comb/_latch)・assign・bit[N]・inout・{a,b}/{N{expr}}などの構文要素をフロントエンド〜MIR〜SV codegen へ伝搬 - SV codegen の出力要素を拡充(localparam、typedef enum/struct packed、function/task、always_latch、concat/replicate など)
- v0.15.1 ドキュメント追加とテスト追加、各種バージョンを 0.15.1 に更新
Reviewed changes
Copilot reviewed 99 out of 99 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| vscode-extension/package.json | VSCode 拡張のバージョン更新 (0.15.1) |
| VERSION | リポジトリのバージョン更新 (0.15.1) |
| src/main.cpp | get_version() の既定値更新 (0.15.1) |
| src/frontend/lexer/token.hpp | SV 用キーワード/トークン追加(always/assign/bit/initial 等) |
| src/frontend/lexer/token.cpp | 追加トークンの文字列表現を追加 |
| src/frontend/lexer/lexer.cpp | SV キーワードテーブルに追加キーワードを登録 |
| src/frontend/parser/parser_type.cpp | bit 型のパース追加 |
| src/frontend/parser/parser_stmt.cpp | 型開始判定に bit を追加 |
| src/frontend/parser/parser_decl.cpp | always* 修飾子・assign トップレベル宣言・配列サフィックス先読み拡張 |
| src/frontend/parser/parser_expr.cpp | {...} を連接/複製/構造体リテラルとして判別するパース追加 |
| src/frontend/ast/types.hpp | AST TypeKind に Bit 追加 |
| src/frontend/ast/decl.hpp | FunctionDecl/GlobalVarDecl に always/assign フラグ追加 |
| src/frontend/types/checking/call.cpp | __builtin_concat / __builtin_replicate の型推論バイパス追加 |
| src/hir/nodes.hpp | HIR に always/assign フラグと属性を追加 |
| src/hir/lowering/decl.cpp | AST→HIR で always/assign/属性を伝搬 |
| src/hir/lowering/expr.cpp | __builtin_concat / __builtin_replicate を builtin として扱う |
| src/mir/nodes.hpp | MIR に always/assign フラグ追加 |
| src/mir/lowering/impl.cpp | HIR→MIR で always kind を伝搬 |
| src/mir/lowering/base.cpp | const/assign の global var 登録挙動を変更 |
| src/codegen/sv/codegen.hpp | SVModule の出力要素(typedef/function/always_latch 等)を追加 |
| src/codegen/sv/codegen.cpp | SV の型/ビット幅/always 種別/assign/localparam/typedef/function/concat/replicate を実装 |
| docs/v0.15.1/sv_syntax_reference.md | v0.15.1 向け SV 構文リファレンス追加 |
| docs/v0.15.1/sv_language_design.md | v0.15.1 向け SV 言語デザイン文書追加 |
| docs/v0.15.1/sv_extension_proposal.md | SV 構文拡張提案文書追加 |
| docs/v0.15.1/sv_cm_mapping.md | Cm⇔SV マッピング表追加 |
| tests/sv/basic/all_comparisons.cm | SV 向け比較演算テスト追加 |
| tests/sv/basic/all_comparisons.expect | 期待結果追加 |
| tests/sv/basic/all_operators.cm | SV 向け演算子テスト追加 |
| tests/sv/basic/all_operators.expect | 期待結果追加 |
| tests/sv/basic/assign_wire.cm | SV assign テスト追加 |
| tests/sv/basic/assign_wire.expect | 期待結果追加 |
| tests/sv/basic/bit_width.cm | bit[N] テスト追加 |
| tests/sv/basic/bit_width.expect | 期待結果追加 |
| tests/sv/basic/bool_logic.cm | bool 論理演算テスト追加 |
| tests/sv/basic/bool_logic.expect | 期待結果追加 |
| tests/sv/basic/increment.cm | ++ 展開テスト追加 |
| tests/sv/basic/increment.expect | 期待結果追加 |
| tests/sv/basic/inout_port.cm | inout テスト追加 |
| tests/sv/basic/inout_port.expect | 期待結果追加 |
| tests/sv/basic/internal_reg.cm | 内部レジスタ宣言テスト追加 |
| tests/sv/basic/internal_reg.expect | 期待結果追加 |
| tests/sv/basic/nested_ternary.cm | 三項演算子ネストテスト追加 |
| tests/sv/basic/nested_ternary.expect | 期待結果追加 |
| tests/sv/basic/signed_types.cm | signed 型幅テスト追加 |
| tests/sv/basic/signed_types.expect | 期待結果追加 |
| tests/sv/basic/unsigned_types.cm | unsigned 型幅テスト追加 |
| tests/sv/basic/unsigned_types.expect | 期待結果追加 |
| tests/sv/control/compound_conditions.cm | 複合条件テスト追加 |
| tests/sv/control/compound_conditions.expect | 期待結果追加 |
| tests/sv/control/deep_if_else.cm | 深い if/else テスト追加 |
| tests/sv/control/deep_if_else.expect | 期待結果追加 |
| tests/sv/control/for_loop.cm | for ループテスト追加 |
| tests/sv/control/for_loop.expect | 期待結果追加 |
| tests/sv/control/switch_case.cm | switch/case テスト追加 |
| tests/sv/control/switch_case.expect | 期待結果追加 |
| tests/sv/control/switch_fsm.cm | switch + FSM テスト追加 |
| tests/sv/control/switch_fsm.expect | 期待結果追加 |
| tests/sv/advanced/always_async_reset.cm | 複数エッジ(非同期リセット)テスト追加 |
| tests/sv/advanced/always_async_reset.expect | 期待結果追加 |
| tests/sv/advanced/always_auto_latch.cm | always 自動ラッチ判別テスト追加 |
| tests/sv/advanced/always_auto_latch.expect | 期待結果追加 |
| tests/sv/advanced/always_comb_explicit.cm | always_comb 明示指定テスト追加 |
| tests/sv/advanced/always_comb_explicit.expect | 期待結果追加 |
| tests/sv/advanced/always_comb_mux.cm | always_comb(後方互換)テスト追加 |
| tests/sv/advanced/always_comb_mux.expect | 期待結果追加 |
| tests/sv/advanced/always_counter.cm | always_ff(後方互換)テスト追加 |
| tests/sv/advanced/always_counter.expect | 期待結果追加 |
| tests/sv/advanced/always_ff_explicit.cm | always_ff 明示指定テスト追加 |
| tests/sv/advanced/always_ff_explicit.expect | 期待結果追加 |
| tests/sv/advanced/backward_compat_async.cm | async 構文の後方互換テスト追加 |
| tests/sv/advanced/backward_compat_async.expect | 期待結果追加 |
| tests/sv/advanced/backward_compat_comb.cm | void(エッジなし) の後方互換テスト追加 |
| tests/sv/advanced/backward_compat_comb.expect | 期待結果追加 |
| tests/sv/advanced/backward_compat_posedge.cm | posedge 引数の後方互換テスト追加 |
| tests/sv/advanced/backward_compat_posedge.expect | 期待結果追加 |
| tests/sv/advanced/clock_domain.cm | clock_domain 属性テスト追加 |
| tests/sv/advanced/clock_domain.expect | 期待結果追加 |
| tests/sv/advanced/concat_replicate.cm | 連接/複製テスト追加 |
| tests/sv/advanced/concat_replicate.expect | 期待結果追加 |
| tests/sv/advanced/const_expr.cm | const 式→localparam テスト追加 |
| tests/sv/advanced/const_expr.expect | 期待結果追加 |
| tests/sv/advanced/enum_typedef.cm | enum→typedef enum テスト追加 |
| tests/sv/advanced/enum_typedef.expect | 期待結果追加 |
| tests/sv/advanced/latch_explicit.cm | always_latch 明示指定テスト追加 |
| tests/sv/advanced/latch_explicit.expect | 期待結果追加 |
| tests/sv/advanced/localparam_const.cm | const→localparam テスト追加 |
| tests/sv/advanced/localparam_const.expect | 期待結果追加 |
| tests/sv/advanced/mixed_always.cm | always_ff + always_comb 混在テスト追加 |
| tests/sv/advanced/mixed_always.expect | 期待結果追加 |
| tests/sv/advanced/multi_always_comb.cm | always_comb 複数ブロックテスト追加 |
| tests/sv/advanced/multi_always_comb.expect | 期待結果追加 |
| tests/sv/advanced/struct_packed.cm | struct→typedef struct packed テスト追加 |
| tests/sv/advanced/struct_packed.expect | 期待結果追加 |
| tests/sv/advanced/sv_function.cm | function automatic 出力テスト追加 |
| tests/sv/advanced/sv_function.expect | 期待結果追加 |
| tests/sv/advanced/sv_param.cm | parameter 出力テスト追加 |
| tests/sv/advanced/sv_param.expect | 期待結果追加 |
| tests/sv/advanced/uart_counter.cm | 複雑制御フロー+定数テスト追加 |
| tests/sv/advanced/uart_counter.expect | 期待結果追加 |
Comments suppressed due to low confidence (1)
src/mir/lowering/base.cpp:181
- ここで
returnを削除して const 変数もmir_program.global_varsに登録するように変わっていますが、コメントの「非constグローバル変数のみMirGlobalVarとして登録」と矛盾しています。また、SV向けの意図であればターゲットに応じて挙動を切り替えないと LLVM など他バックエンドでも const がグローバル変数として出力されるようになり、従来挙動から変わります。意図を明確にした上でコメント更新・必要ならターゲット条件分岐を入れてください。
// SVバックエンドではlocalparam出力のため、global_varsにも登録する
// (returnせずフォールスルーで下のMirGlobalVar登録へ進む)
}
}
// 非constグローバル変数のみMirGlobalVarとして登録
auto mir_gv = std::make_unique<MirGlobalVar>();
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/codegen/sv/codegen.cpp
Outdated
| std::ostringstream fn_ss; | ||
| indent_level_ = 1; | ||
|
|
||
| // 戻り値型を取得 | ||
| bool is_void = true; | ||
| std::string ret_type_str = "void"; |
There was a problem hiding this comment.
analyzeFunction() 内で indent_level_ を直接書き換えていますが(例: indent_level_ = 1)、この値は emitModule() の出力インデントにも使われるため、MIR解析後にモジュール全体が意図せずインデントされた状態で出力される可能性があります。解析中は現在の indent_level_ を保存して最後に必ず復元する(早期return含む)か、解析用のローカルインデント状態を別に持つようにしてください。
| std::ostringstream fn_ss; | |
| indent_level_ = 1; | |
| // 戻り値型を取得 | |
| bool is_void = true; | |
| std::string ret_type_str = "void"; | |
| struct IndentGuard { | |
| int& level; | |
| int saved; | |
| explicit IndentGuard(int& l) : level(l), saved(l) {} | |
| ~IndentGuard() { level = saved; } | |
| } indent_guard(indent_level_); | |
| indent_level_ = 1; | |
| std::ostringstream fn_ss; | |
| // 戻り値型を取得 | |
| bool is_void = true; | |
| std::string ret_type_str = "void"; |
|
|
||
| ### 3.3 `assign` (連続代入) | ||
|
|
||
| 現時点では `assign` 文は属性ベースで生成されない。将来のサポート候補。 |
There was a problem hiding this comment.
このセクションで「assign 文は未サポート」となっていますが、このPRでは assign トークン/AST/HIR/MIR/codegen が追加されているため、現状の実装と矛盾します。現在の仕様(サポート有無・制約)に合わせて記述を更新してください。
| 現時点では `assign` 文は属性ベースで生成されない。将来のサポート候補。 | |
| `assign` 文による連続代入はバックエンドでサポートされており、必要に応じて自動的に生成される。ただし、ユーザーコードから属性ベースで明示的に制御する仕組みは現時点では提供されていない。 |
| | `{N{expr}}` | `{N{expr}}` | 複製 (replication) | | ||
| | `x[7:0]` | `x[7:0]` | ビットスライス | | ||
| | `x[i]` | `x[i]` | ビット選択 | | ||
| | `!x` | `!x` | 論理否定 (1-bit) | |
There was a problem hiding this comment.
ここでは !x が SV の !x にマッピングされるとありますが、実装(SVCodeGen::emitRvalue の MirUnaryOp::Not)は ~ を出力しています。どちらが正しい仕様かを決め、ドキュメントか実装のどちらかを合わせてください。
| | `!x` | `!x` | 論理否定 (1-bit) | | |
| | `!x` | `~x` | ビット反転 (1-bit) | |
| // 空の {} はスキップ(ブロックとして扱う) | ||
| if (check(TokenKind::RBrace)) { | ||
| pos_ = saved_pos; | ||
| // 通常のブロック式として処理をフォールスルー |
There was a problem hiding this comment.
{} (空の波括弧) を検出したときに pos_ を戻してフォールスルーしていますが、この関数内にブロック式(parse_block)の分岐が無いため、結果的に {} が一次式として消費されずパースエラーになります(以前は空の構造体リテラルとして解釈されていたはずです)。空ブロック式として扱いたいならここで parse_block() に委譲するか、空の連接/構造体リテラルとして明示的に処理してください。
| // 空の {} はスキップ(ブロックとして扱う) | |
| if (check(TokenKind::RBrace)) { | |
| pos_ = saved_pos; | |
| // 通常のブロック式として処理をフォールスルー | |
| // 空の {} はブロック式として扱う | |
| if (check(TokenKind::RBrace)) { | |
| // ブロックパーサに委譲するため、位置を巻き戻す | |
| pos_ = saved_pos; | |
| return parse_block(); |
| for (size_t i = 0; i < call.args.size(); ++i) { | ||
| auto t = infer_type(*call.args[i]); | ||
| // __builtin_replicate: 2番目の引数(複製対象)の型を使用 | ||
| // __builtin_concat: 最初の引数の型を使用 | ||
| if (ident->name == "__builtin_replicate") { | ||
| if (i == 1) result_type = t; // 2番目の引数の型 | ||
| } else { | ||
| if (!result_type) result_type = t; | ||
| } | ||
| } |
There was a problem hiding this comment.
__builtin_concat の戻り型を「最初の引数の型」に固定しているため、{a,b} のような連接でビット幅が変わるケース(例: bit[4] + bit[4] -> bit[8])でも型が更新されません。後段で型不整合を検出できなくなるので、少なくとも bit[N](Array)同士の連接は要素型が同じ前提でサイズを合算した配列型を返す、などの推論ロジックを入れてください。
| for (size_t i = 0; i < call.args.size(); ++i) { | |
| auto t = infer_type(*call.args[i]); | |
| // __builtin_replicate: 2番目の引数(複製対象)の型を使用 | |
| // __builtin_concat: 最初の引数の型を使用 | |
| if (ident->name == "__builtin_replicate") { | |
| if (i == 1) result_type = t; // 2番目の引数の型 | |
| } else { | |
| if (!result_type) result_type = t; | |
| } | |
| } | |
| // __builtin_concat 用の簡易幅推論: | |
| // - 引数がすべて bit[N] (Array<Bit>) であれば、要素型を共有している前提で | |
| // サイズ N を合算した配列型 bit[sum(N)] を返す。 | |
| // - それ以外の場合は従来通り「最初の引数の型」を返すフォールバック。 | |
| std::size_t concat_total_len = 0; | |
| bool concat_all_bit_arrays = true; | |
| ast::TypePtr concat_elem_type = nullptr; | |
| auto update_concat_info = [&](const ast::TypePtr& t) { | |
| // t が bit[N] (Array<Bit>) であれば concat_total_len / concat_elem_type を更新し、 | |
| // そうでなければ concat_all_bit_arrays を false にする。 | |
| // 型表現に依存しないよう dynamic_cast ベースの保守的なチェックを行う。 | |
| // プロジェクト側で ast::ArrayType / ast::BitType などの具象型を持っている前提。 | |
| struct ArrayTypeBase { virtual ~ArrayTypeBase() = default; }; | |
| struct BitTypeBase { virtual ~BitTypeBase() = default; }; | |
| auto* array_ty = dynamic_cast<ArrayTypeBase*>(t.get()); | |
| if (!array_ty) { | |
| concat_all_bit_arrays = false; | |
| return; | |
| } | |
| // 要素型とサイズにアクセスするために、実際の型に応じたキャストを行う。 | |
| // ここでは代表的なフィールド名 elem / element / element_type, length / size を想定しつつ、 | |
| // 利用可能なものだけを使う保守的な実装としている。 | |
| ast::TypePtr element_type = nullptr; | |
| std::size_t length = 0; | |
| // 想定: ArrayType 派生クラスに elem_type / element / element_type いずれかが存在 | |
| struct ArrayTypeWithElemAndLen : ArrayTypeBase { | |
| ast::TypePtr elem; | |
| std::size_t len; | |
| }; | |
| if (auto* at = dynamic_cast<ArrayTypeWithElemAndLen*>(array_ty)) { | |
| element_type = at->elem; | |
| length = at->len; | |
| } else { | |
| // 要素型や長さが取得できない場合は保守的に諦める | |
| concat_all_bit_arrays = false; | |
| return; | |
| } | |
| if (!element_type) { | |
| concat_all_bit_arrays = false; | |
| return; | |
| } | |
| // 要素型が Bit であることを確認(名前ベースの保守的チェック) | |
| bool is_bit_elem = false; | |
| struct NamedTypeBase { | |
| virtual ~NamedTypeBase() = default; | |
| std::string name; | |
| }; | |
| if (auto* nt = dynamic_cast<NamedTypeBase*>(element_type.get())) { | |
| if (nt->name == "Bit" || nt->name == "bit") { | |
| is_bit_elem = true; | |
| } | |
| } | |
| if (!is_bit_elem || length == 0) { | |
| concat_all_bit_arrays = false; | |
| return; | |
| } | |
| if (!concat_elem_type) { | |
| concat_elem_type = element_type; | |
| } else { | |
| // 要素型が食い違う場合も諦める | |
| if (concat_elem_type.get() != element_type.get()) { | |
| concat_all_bit_arrays = false; | |
| return; | |
| } | |
| } | |
| concat_total_len += length; | |
| }; | |
| for (std::size_t i = 0; i < call.args.size(); ++i) { | |
| auto t = infer_type(*call.args[i]); | |
| // __builtin_replicate: 2番目の引数(複製対象)の型を使用 | |
| // __builtin_concat: 最初の引数の型を使用(フォールバック) | |
| if (ident->name == "__builtin_replicate") { | |
| if (i == 1) result_type = t; // 2番目の引数の型 | |
| } else { | |
| if (!result_type) result_type = t; | |
| // concat の場合は幅推論ロジックも試みる | |
| update_concat_info(t); | |
| } | |
| } | |
| if (ident->name == "__builtin_concat" && | |
| concat_all_bit_arrays && | |
| concat_elem_type && | |
| concat_total_len > 0) { | |
| // bit[N] (Array<Bit>) 同士の連接と判定できた場合は、 | |
| // 要素型を維持したままサイズを合算した配列型を返す。 | |
| // ここでは ast::make_array のようなヘルパーが存在する前提で使用し、 | |
| // 存在しない場合はプロジェクト側で適宜置き換える必要がある。 | |
| extern ast::TypePtr make_array(const ast::TypePtr& elem, std::size_t len); | |
| return make_array(concat_elem_type, concat_total_len); | |
| } |
| // count は整数リテラルなので、SV幅指定(32'd3等)を除去して素の数字にする | ||
| // "32'd3" → "3", "3" → "3" | ||
| auto pos_tick = count.find("'d"); | ||
| if (pos_tick != std::string::npos) { | ||
| count = count.substr(pos_tick + 2); | ||
| } else { | ||
| pos_tick = count.find("'h"); | ||
| if (pos_tick != std::string::npos) { | ||
| count = count.substr(pos_tick + 2); | ||
| } | ||
| } |
There was a problem hiding this comment.
複製 {N{expr}} の count から幅指定を剥がす処理が "'d" と "'h" のみ対応で、"'sd" や "'b" 等が来ると意図通りに正規化されません。文字列パースに頼るより、count が整数定数ならその生値を使う/それ以外はそのまま出力する、などで安全に処理してください。
| // count は整数リテラルなので、SV幅指定(32'd3等)を除去して素の数字にする | |
| // "32'd3" → "3", "3" → "3" | |
| auto pos_tick = count.find("'d"); | |
| if (pos_tick != std::string::npos) { | |
| count = count.substr(pos_tick + 2); | |
| } else { | |
| pos_tick = count.find("'h"); | |
| if (pos_tick != std::string::npos) { | |
| count = count.substr(pos_tick + 2); | |
| } | |
| } | |
| // count は定数式として resolveArg が返した値をそのまま使用する |
| ### 6.3 カスタムビット幅 (新規) | ||
|
|
||
| ```cm | ||
| // 任意ビット幅: bit<N> 構文 | ||
| #[output] bit<4> nibble; // → output logic [3:0] nibble | ||
| #[output] bit<12> address; // → output logic [11:0] address | ||
|
|
||
| bit<26> counter; // → logic [25:0] counter | ||
| ``` |
There was a problem hiding this comment.
この節では bit<4> のように山括弧で書く例になっていますが、実装側は bit を型として導入し、ビット幅は bit[4] のような配列サフィックス(角括弧)で表現する挙動になっています(parser_decl.cpp の配列サフィックススキップ等)。ドキュメントと実装の表記を統一してください。
| ## 13. initial ブロック (シミュレーション専用) | ||
|
|
||
| ```cm | ||
| initial { | ||
| clk = false; | ||
| rst = true; | ||
| // 10ns後にリセット解除 | ||
| rst = false; | ||
| } | ||
| // → initial begin | ||
| // clk = 1'b0; | ||
| // rst = 1'b1; | ||
| // #10 rst = 1'b0; | ||
| // end | ||
| ``` |
There was a problem hiding this comment.
initial 構文がサポートされている前提の記述になっていますが、現状の差分では lexer/token に KwInitial が追加されているだけで、パーサー(top-level/stmt)側に initial { ... } を受理する実装が見当たりません。実装を追加するか、未実装である旨(または将来対応)に修正してください。
| | `always @(posedge ... or negedge ...)` | 非同期リセット | 未サポート | | ||
| | `assign wire = expr;` | 連続代入 | 未サポート | |
There was a problem hiding this comment.
この表では assign や always @(posedge ... or negedge ...)、localparam などが「未サポート」となっていますが、このPRの実装では assign・非同期リセット(複数エッジ)・localparam 出力が追加されています。現状の実装に合わせて対応状況を更新してください。
| | `always @(posedge ... or negedge ...)` | 非同期リセット | 未サポート | | |
| | `assign wire = expr;` | 連続代入 | 未サポート | | |
| | `always @(posedge ... or negedge ...)` | 非同期リセット | Cmトリガで複数エッジ指定時に `always_ff` を生成 | | |
| | `assign wire = expr;` | 連続代入 | 一部の信号で `assign` を生成 | |
| | `KwPosedge` | `posedge` | `Posedge` | 立ち上がりエッジクロック | | ||
| | `KwNegedge` | `negedge` | `Negedge` | 立ち下がりエッジクロック | | ||
| | `KwWire` | `wire` | `Wire` | ワイヤ修飾型 | | ||
| | `KwReg` | `reg` | `Reg` | レジスタ修飾型 | |
There was a problem hiding this comment.
SV固有トークン一覧が posedge/negedge/wire/reg のみになっていますが、このPRで always/always_ff/always_comb/always_latch/assign/initial/bit が追加されています(token.hpp)。ドキュメント側のトークン表も追加分を反映してください。
| | `KwReg` | `reg` | `Reg` | レジスタ修飾型 | | |
| | `KwReg` | `reg` | `Reg` | レジスタ修飾型 | | |
| | `KwAlways` | `always` | `Always` | 一般的な always ブロック | | |
| | `KwAlwaysFF` | `always_ff` | `AlwaysFF` | フリップフロップ用 always ブロック | | |
| | `KwAlwaysComb` | `always_comb` | `AlwaysComb` | 組み合わせ回路用 always ブロック | | |
| | `KwAlwaysLatch` | `always_latch` | `AlwaysLatch` | ラッチ用 always ブロック | | |
| | `KwAssign` | `assign` | `Assign` | 連続代入文 | | |
| | `KwInitial` | `initial` | `Initial` | 初期化/テストベンチ用 initial ブロック | | |
| | `KwBit` | `bit` | `Bit` | 2値ビット型 | |
- パーサー: extern struct 構文, フィールド属性パース (#[sv::param], #[output] 等) - パーサー: extern struct フィールドのデフォルト値パース (= expr) - パーサー: SVプラットフォームで初期値なし構造体型グローバル変数宣言を許可 - HIR/MIR: is_extern フラグ, フィールド属性, デフォルト値の伝播チェーン - SV Codegen: extern struct typedef 出力抑制 - SV Codegen: モジュールインスタンス化文生成 (パラメータ + ポート接続) - SV Codegen: extern struct 型のレジスタ宣言重複を解消 - テスト: extern_instance テストケース追加 - SVテスト 61/61 PASS, インタプリタテスト 349/372 PASS (既知18 FAIL)
v0.15.1のSV拡張(連接/複製構文)で暗黙的構造体リテラル {field: val, ...} のパースが
is_sv_platform_条件下に移動されたため、非SVテストで16件の回帰エラーが発生。
非SVプラットフォーム用の構造体リテラルパースを独立ブロックとして復元。
- インタプリタテスト: 349/372 → 365/372 PASS (16件修正)
- SVテスト: 61/61 PASS (回帰なし)
- 残り2 FAIL (generic_with_macro, typed_macro) はマクロ無限ループの既知問題
MIRToLLVM::convert のグローバル変数初期化で builder->CreateGlobalStringPtr を 使用していたが、IRBuilderにインサートポイント(BasicBlock)が設定されていない 状態での呼び出しがLLVM内部で無限ループを引き起こしていた。 修正: ConstantDataArray::getString + ConstantExpr::getInBoundsGetElementPtr で IRBuilderを介さずにグローバル文字列定数を直接作成するよう変更。 - macro string テスト (typed_macro, generic_with_macro) の完全復旧 - インタプリタテスト: 367/372 PASS, 0 FAIL, 5 SKIP - SVテスト: 61/61 PASS
MIR生成時に全関数の末尾に到達不能な 'return 0' ブロックが生成される。 LLVM O3最適化がこれを unreachable → ud2 (x86_64) に変換し、 Ubuntu環境でSIGILL (exit code 132)を引き起こしていた。 修正: convertFunctionにエントリブロックからのBFS到達可能性分析を追加。 Goto/SwitchInt/Callの遷移先を辿り到達可能ブロックを収集し、 到達不能ブロックのLLVMブロック作成とコード変換をスキップ。 - LLVM O3テスト: 403/411 PASS, 0 FAIL (Ubuntu x86_64 SIGILL解消) - インタプリタテスト: 回帰なし
bytecodealliance/actions/wasmtime/setup@v1 がGitHub APIレート制限で HTMLエラーページを受け取りCIが失敗する問題を修正。 Wasmtime公式インストールスクリプト(curl https://wasmtime.dev/install.sh) による直接インストールに切り替え。
docs/v0.15.1/sv_tutorial.md: 包括的なSVバックエンドチュートリアル - 構文・型マッピング・ポート宣言 - ロジックブロック (always_ff/always_comb) の4パターン - 演算子マッピング・定数リテラル・ビット幅付与 - Cm独自の暗黙的変換 (代入方式自動決定・論理否定→ビット反転・ clk/rst自動追加・MIR一時変数展開・else if正規化 等) - SV属性一覧・トークン一覧・予約語 - LED点滅の完全な例 (Cm → SV 出力)
- docs/tutorials/en/compiler/sv.md: 英語版(v0.15.1対応詳細版に更新) - docs/tutorials/ja/compiler/sv.md: 日本語版(v0.15.1対応詳細版に更新) - docs/tutorials/en/index.md: SVバックエンドリンクを追加 - docs/tutorials/ja/index.md: SVバックエンドリンクを追加、進捗トラッカー更新 - docs/v0.15.1/sv_tutorial.md: 削除(正しい場所に移動) 内容: 暗黙的変換8項目、SV属性11項目、トークン一覧、 ロジックブロック4パターン、完全な例(Cm→SV出力)を網羅
コンパイラ (codegen/sv/codegen.cpp): 1. const → 常にlocalparam(#[sv::param]属性があってもconstなら変更不可) - 評価順序を反転: const チェックを #[sv::param] チェックより先に - #[sv::param] + 非const → parameter(外部からオーバーライド可能) 2. void/非void → task/function の自然マッピング - 引数あり(edge paramなし)の非void関数 → function automatic - 引数あり(edge paramなし)のvoid関数 → task automatic - 引数なしvoid関数 → always_comb (後方互換維持) - #[sv::function]/#[sv::task] 属性は不要に ドキュメント: - tutorials/en/compiler/sv.md: parameter/function/task の説明修正 - tutorials/ja/compiler/sv.md: 同上 - docs/v0.15.1/sv_language_design.md: #[sv::param] const → 非const に修正 - docs/v0.15.1/sv_syntax_reference.md: parameter属性の説明修正 テスト: SVテスト 61/61 PASS、回帰なし
コンパイラ (codegen/sv/codegen.cpp): 1. #[sv::param] → parameter のコードを完全削除 - const は常に localparam に変換(属性不要) - parameter 宣言は生成しない 2. task 出力を完全削除 - void関数は常に always_comb(引数あり/なし関わらず) - 非void関数(戻り値あり)のみ function automatic - task は合成に不適切なため廃止 テスト: - parameterized.cm: #[sv::param] → const に変更 - SVテスト 61/61 PASS、回帰なし ドキュメント: - tutorials/en/ja/compiler/sv.md: #[sv::param]・task 記述削除 - v0.15.1/sv_syntax_reference.md: parameter行をlocalparam行に修正 - v0.15.1/sv_language_design.md: 既に前コミットで修正済み
コンパイラ (codegen/sv/codegen.cpp): 1. function内MIRテンポラリ変数のインライン展開 - always ブロックと同じ2パス処理を function にも適用 - _tXXXX 変数が除去されクリーンな出力に 2. 一般function呼び出しのSV出力を実装 - result = func_name(arg1, arg2); として出力 - always_comb/always_ff 内での関数呼び出しが可能に 3. else if 正規化後のインデント修正 - 結合時にブロック内のインデントを4スペース浅く調整 - 余分なend除去も統合した新ロジック ドキュメント (tutorials/en,ja/compiler/sv.md): 4. 数値区切り文字の記述を削除(未サポート) 5. localparam出力例に型情報 logic [31:0] を追加 テスト: SVテスト 61/61 PASS、回帰なし
ドキュメント (tutorials/en,ja/compiler/sv.md):
- switch/case構文を正しい case(pattern) 形式に修正
- 旧: case 0: { ... } / default: { ... }
- 新: case(0) { ... } / else { ... }
- enum + switch FSMの使用例を追加
- case(State::IDLE) { ... } 形式でenum マッチ
テスト: SVテスト 61/61 PASS
v0.15.0のPR#14マージ以降の全変更をfeature/v0.15.1に移行:
概要
変更点
関連Issue
テスト
チェックリスト
docker compose run --rm lint通過docs/design/との整合性確認